package yxy.cherry.data;

import org.redisson.api.RMap;
import yxy.apple.logger.Logger;
import yxy.apple.util.ReflectionUtility;
import yxy.apple.util.redisson.RedisConnection;
import yxy.cherry.data.bean.model.DataClass;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class DataCenter {

    static private DataCenter instance;
    protected static Logger logger = Logger.create(DataCenter.class);

    static public void init(RedisConnection connection, boolean cache) {
        if (instance == null) {
            instance = new DataCenter();
            instance.connection = connection;
            instance.cache = cache;
//            //不开启缓存
//            if (cache) {
//                instance.init();
//            }
            instance.init();
        }
    }

    //gm后台调用
    static public void initForGM(RedisConnection connection, boolean cache) {
        if (instance == null) {
            instance = new DataCenter();
            instance.connection = connection;
            instance.cache = cache;
        }
    }

    private RedisConnection connection;
    private boolean cache;// 缓存功能开关

    private DataCenter() {
    }

    private void init() {
        Set<Class<? extends DataClass>> dataTypeSet = ReflectionUtility.getSubTypesOf("yxy.cherry.data.bean", DataClass.class);
        for (Class<? extends DataClass> clazz : dataTypeSet) {
            getAllData(clazz);
        }
    }

    synchronized static public <T> T getData(int id, Class<T> clazz) {
        return getData("v1.0.0.0", String.valueOf(id), clazz);
    }

    synchronized static public <T> T getData(String code, Class<T> clazz) {
        return getData("v1.0.0.0", code, clazz);
    }

    synchronized static public <T> T getData(String version, String code, Class<T> clazz) {
        try {
            return instance._getData(version, code, clazz);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    synchronized static public <T> Map<String, T> getAllData(Class<T> clazz) {
        return instance._getAllData("v1.0.0.0", clazz);
    }

    private <T> T _getData(String version, String code, Class<T> clazz) throws Exception {
        return _getAllData(version, clazz).get(code);
    }

    @SuppressWarnings("unchecked")
    private <T> Map<String, T> _getAllData(String version, Class<T> clazz) {
        if (cache && cacheMap.containsKey(clazz)) {
            return cacheMap.get(clazz);
        }

        //比较md5码，不一致就获取缓存最新的数据
        checkMd5AndSaveDate(clazz, version);
        return cacheMap.get(clazz);
    }

    //比较md5码
    private <T> void checkMd5AndSaveDate(Class<T> clazz, String version) {
        //todo 优先判断内存有没有md5码
        String md5FromRedis = getMD5(clazz);//缓存中对应表的md5码
        String filename = String.format("%s.json", clazz.getSimpleName());
        String md5FromCache = md5CacheMap.get(filename); //内存中对应表的md5码

        if (md5FromCache == null || md5FromCache.equals("")) {
            logger.info("DataCenter中的------------" + filename + "----------对应内存表有没有md5码,获取最新数据放内存");
            saveDate(clazz, version, filename, md5FromRedis);
            return;
        }

        //todo 内存中的md5和缓存的md5不一样，从缓存中获取最新的并放内存
        if (md5FromCache != null && !md5FromCache.equals(md5FromRedis)) {
            logger.info("DataCenter中的------------" + filename + "----------对应内存表md5码和缓存不一致，获取最新数据放内存");
            saveDate(clazz, version, filename, md5FromRedis);
            return;
        }
    }


    synchronized static public <T> String getMD5(Class<T> clazz) {
        return instance._getMD5("v1.0.0.0", clazz);
    }

    private <T> String _getMD5(String version, Class<T> clazz) {
        RMap<String, String> rmap = connection.client().getMap("DATA:" + version + ":MD5");
        String filename = String.format("%s.json", clazz.getSimpleName());
        return rmap.get(filename);
    }

    /**
     * 缓存
     */
    @SuppressWarnings("rawtypes")
    private Map<Class, Map> cacheMap = new HashMap<>();


    /**
     * md5缓存
     */
    private Map<String, String> md5CacheMap = new HashMap<>();

    /**
     * 存md5数据和表数据到内存
     *
     * @param <T>
     * @param clazz
     * @param version
     * @param filename
     * @param md5FromRedis
     */
    private <T> void saveDate(Class<T> clazz, String version, String filename, String md5FromRedis) {
        String key = String.format("DATA:%s:DATAS:%s", version, clazz.getSimpleName());
        RMap<String, T> rmap = connection.client().getMap(key);
        HashMap<String, T> map = new HashMap<>(rmap);
        cacheMap.put(clazz, map);
        md5CacheMap.put(filename, md5FromRedis);
    }

}
